Skip to content

feat(events): support LANGWATCH_PROJECT_ID via X-Project-Id header#619

Open
0xdeafcafe wants to merge 3 commits into
mainfrom
feat/langwatch-project-id-auth
Open

feat(events): support LANGWATCH_PROJECT_ID via X-Project-Id header#619
0xdeafcafe wants to merge 3 commits into
mainfrom
feat/langwatch-project-id-auth

Conversation

@0xdeafcafe

@0xdeafcafe 0xdeafcafe commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Why

LangWatch is moving to API keys that aren't bound to a single project; clients must send the project ID separately so the server can scope the request. Both event reporters currently send only an API key, so multi-project keys can't authorise.

What changed

  • Add LANGWATCH_PROJECT_ID env var + project_id / projectId config to the Python and JS event reporters, with the same resolution order as api_key (explicit → env → default empty).
  • Switch the request authentication to Authorization: Bearer <api_key> only and drop the legacy X-Auth-Token dual-emit on both reporters — the new server contract is bearer-only.
  • Emit X-Project-Id: <project_id> only when configured; project-bound API keys keep working with no extra config.

Test plan

  • python/tests/test_event_reporter.py — added three tests for project_id (explicit, env fallback, env→explicit precedence). Updated existing tests to assert Authorization: Bearer … instead of X-Auth-Token. All 11 tests pass.
  • javascript/src/events/__tests__/event-reporter.test.ts — new file. Five tests: Authorization: Bearer is sent and X-Auth-Token is absent; X-Project-Id is sent only when projectId is configured; POST is skipped when apiKey is empty; setUrl is returned from a successful response.
  • TypeScript: pnpm typecheck is clean for the touched files; pre-existing voice-module errors (missing ffmpeg-static, elevenlabs, @amiceli/vitest-cucumber) are unchanged from main.

How I can prove I was successful

No playable artifact — see Test plan. Auth header behaviour is covered by both the Python and JS suites; the two reporter implementations mirror each other.

Copilot AI review requested due to automatic review settings June 5, 2026 12:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for multi-project LangWatch API keys by allowing both the Python and JavaScript event reporters to send a project scope identifier via X-Project-Id when configured, while standardizing authentication on Authorization: Bearer <api_key>.

Changes:

  • Python: add project_id support (env + constructor) and conditionally emit X-Project-Id; remove legacy X-Auth-Token.
  • JavaScript: add projectId plumbing from run()EventBusEventReporter, conditionally emitting X-Project-Id; switch to Authorization: Bearer ....
  • Tests/docs: expand Python request-header tests to cover X-Project-Id behavior and bearer-only auth.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
python/tests/test_event_reporter.py Updates header assertions for bearer-only auth and adds coverage for X-Project-Id emission and env fallback.
python/scenario/config/langwatch.py Introduces project_id setting under the LANGWATCH_ env prefix.
python/scenario/_events/event_reporter.py Adds project_id resolution and conditionally includes X-Project-Id; removes X-Auth-Token dual-emit.
javascript/src/runner/run.ts Extends LangWatch runtime config to include projectId and passes it into the event system.
javascript/src/events/event-reporter.ts Switches to bearer auth and conditionally emits X-Project-Id when configured.
javascript/src/events/event-bus.ts Extends EventBus constructor config shape to accept/pass through projectId.
javascript/src/config/env.ts Adds LANGWATCH_PROJECT_ID to the validated environment schema.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread python/tests/test_event_reporter.py
drewdrewthis
drewdrewthis previously approved these changes Jun 9, 2026

@drewdrewthis drewdrewthis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

LangWatch is moving to API keys that aren't bound to a single project;
clients must send the project ID separately so the server can scope the
request. Both event reporters now accept project_id/projectId (with
LANGWATCH_PROJECT_ID env var) and emit X-Project-Id when set.

Also switches authentication to Authorization: Bearer only and drops
the legacy X-Auth-Token dual-emit on both reporters — the new server
contract is bearer-only.
Adds parity with the Python suite — checks Authorization: Bearer is sent,
X-Auth-Token is absent, X-Project-Id is sent only when projectId is
configured, POST is skipped when apiKey is empty, and setUrl is returned
from a successful response.
Resolves three JS conflicts where main (#545) also added cfg.langwatch
config plumbing and moved LangwatchConfig into ../domain:

- event-bus.ts / event-reporter.ts: keep main's projectId?: string
  signature and string | undefined field type; the PR's Authorization:
  Bearer headers replace the duplicate X-Auth-Token block auto-merge
  left in postEvent.
- run.ts: drop the inline LangwatchConfig (now imported from
  ../domain) and merge the env / cfg.langwatch / options.langwatch
  resolution into a single three-tier fallback for endpoint, apiKey,
  and projectId.

The previously-failing voice/test_feature_file_contract.py @Unit count
also resolves automatically — main's tag bump arrives via this merge.
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Both the Python and JavaScript SDKs gain support for an optional LANGWATCH_PROJECT_ID configuration field. EventReporter in both SDKs switches from the legacy X-Auth-Token header to Authorization: Bearer <apiKey>, and conditionally emits an X-Project-Id header when a project ID is configured. The JS runner gains an env-var fallback for projectId.

Changes

LangWatch Project ID and Bearer Auth

Layer / File(s) Summary
Config schema extension
javascript/src/config/env.ts, python/scenario/config/langwatch.py
Adds optional LANGWATCH_PROJECT_ID to the JS envSchema and project_id field to Python LangWatchSettings, with updated docstrings describing the env var and programmatic usage.
EventReporter: Bearer auth and X-Project-Id
python/scenario/_events/event_reporter.py, javascript/src/events/event-reporter.ts
Replaces X-Auth-Token with Authorization: Bearer in both SDKs. Python EventReporter gains an optional project_id constructor parameter that falls back to LangWatchSettings.project_id; both implementations conditionally add X-Project-Id when project_id is set.
JS runner projectId env-var fallback
javascript/src/runner/run.ts
EventBus initialization now uses envConfig.LANGWATCH_PROJECT_ID as a third fallback source for projectId after options and cfg.
Tests
javascript/src/events/__tests__/event-reporter.test.ts, python/tests/test_event_reporter.py
JS tests add makeEvent/mockOkFetch helpers and a full EventReporter describe block covering Bearer auth, conditional X-Project-Id, skip-on-empty-key, and setUrl extraction. Python tests assert X-Auth-Token absence, X-Project-Id conditional behavior via constructor and env-var fallback with precedence rules, and remove legacy header assertions from existing tests.

Possibly related PRs

  • langwatch/scenario#545: Wires projectId through run()EventBusEventReporter with conditional X-Project-Id header logic in event-reporter.ts, directly overlapping with this PR's changes.

Suggested labels

pr-ready, ai-reviewed

Suggested reviewers

  • Aryansharma28
  • sergioestebance
  • rogeriochaves

Poem

🐇 A token of auth, now Bearer and bright,
The project ID hops in, scoping things right.
X-Auth-Token? Retired, put out to the field,
Both Python and JS, their headers re-sealed.
The env var fallback keeps nothing amiss—
This bunny approves, with a satisfying bliss! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main change: adding LANGWATCH_PROJECT_ID support via X-Project-Id header, which is the primary feature across both Python and JavaScript event reporters.
Description check ✅ Passed The PR description comprehensively explains why the change was needed, what was changed (including specific files and implementation details), testing approach, and success criteria.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/langwatch-project-id-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

Automated low-risk assessment

This PR was evaluated against the repository's Low-Risk Pull Requests procedure and does not qualify as low risk.

The PR modifies authentication/authorization behavior by removing the legacy X-Auth-Token dual-emit and switching both Python and JS event reporters to Authorization: Bearer only, and it also introduces project scoping via a new X-Project-Id header and LANGWATCH_PROJECT_ID config. Because it changes authentication and request-scoping logic (affecting how requests are authorized), it does not meet the low-risk criteria and requires a normal review.

This PR requires a manual review before merging.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/tests/test_event_reporter.py`:
- Around line 70-72: The assertion checking that "X-Project-Id" is not in
request.headers can fail nondeterministically if the LANGWATCH_PROJECT_ID
environment variable is set, since EventReporter falls back to using that env
var for project_id. Before constructing the EventReporter instance in this test,
explicitly clear or unset the LANGWATCH_PROJECT_ID environment variable to
ensure the test runs in isolation from ambient environment state and produces
deterministic results.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3472c1bb-d73e-4ee2-832c-e38c40459417

📥 Commits

Reviewing files that changed from the base of the PR and between b819849 and f918dee.

📒 Files selected for processing (7)
  • javascript/src/config/env.ts
  • javascript/src/events/__tests__/event-reporter.test.ts
  • javascript/src/events/event-reporter.ts
  • javascript/src/runner/run.ts
  • python/scenario/_events/event_reporter.py
  • python/scenario/config/langwatch.py
  • python/tests/test_event_reporter.py

Comment on lines +70 to +72
# Without project_id, no X-Project-Id header is sent — the API key is
# assumed to be project-bound.
assert "X-Project-Id" not in request.headers

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stabilize the “no X-Project-Id” assertion against ambient environment state.

Line 70-Line 72 can fail nondeterministically when LANGWATCH_PROJECT_ID is set in CI/dev shells, because EventReporter falls back to env project_id. Clear that env var in this test before constructing EventReporter.

Suggested patch
-async def test_post_event_sends_correct_request(caplog: LogCaptureFixture) -> None:
+async def test_post_event_sends_correct_request(
+    caplog: LogCaptureFixture,
+    monkeypatch: pytest.MonkeyPatch,
+) -> None:
+    monkeypatch.delenv("LANGWATCH_PROJECT_ID", raising=False)
     endpoint = "https://app.langwatch.ai"
     api_key = "test-api-key"
     event = _make_event()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/tests/test_event_reporter.py` around lines 70 - 72, The assertion
checking that "X-Project-Id" is not in request.headers can fail
nondeterministically if the LANGWATCH_PROJECT_ID environment variable is set,
since EventReporter falls back to using that env var for project_id. Before
constructing the EventReporter instance in this test, explicitly clear or unset
the LANGWATCH_PROJECT_ID environment variable to ensure the test runs in
isolation from ambient environment state and produces deterministic results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants